﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SilkenWeb.Reg.UI.Properties;
using System.Globalization;

namespace SilkenWeb.Reg.UI
{
    public partial class MainForm : Form
    {

        #region | Constants |

        private const string STR_Caption = "REG - Making Your Mind Up!";
        private const string STR_CandidateSelected = "REG has selected '{0}'\n\nHave fun!";
        private const string STR_Reintroduction = "REG would like you to allw you to reintroduce 1 rejected item.\n\nSimply drag the item you would like to reintroduce back into the Active Candidates list.";
        private const string STR_ConfirmClose = "Do you really want to close down REG?";

        private const string TYP_Candidate = "SilkenWeb.Reg.Candidate";

        private const string VLD_NumericInputOnly = "Must be numeric.";

        #endregion

        #region | Properties & Fields |

        private CandidateListManager candidateManager = new CandidateListManager(Convert.ToInt32(Settings.Default["ReintroductionFactor"], CultureInfo.CurrentCulture));

        #endregion

        #region | Construction |

        public MainForm()
        {
            InitializeComponent();
            SetSelectionModeForAllListBoxes(SelectionMode.None);
            BindData();
            AddTestCandidates();
        }

        #endregion

        #region | Event Handlers |

        #region | Form |

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (ShowMessageBox(STR_ConfirmClose, STR_Caption, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                e.Cancel = true;
            }
            else
            {
                SetSelectionModeForAllListBoxes(SelectionMode.One);
            }
        }

        #endregion

        #region | btnAddCandidate |

        private void btnAddCandidate_Click(object sender, EventArgs e)
        {
            AddCandidate();
        }

        #endregion

        #region | btnClearAllCandidates |

        private void btnClearAllCandidates_Click(object sender, EventArgs e)
        {
            RemoveAllCandidates();
        }

        #endregion

        #region | btnReset |

        private void btnReset_Click(object sender, EventArgs e)
        {
            Reset();
        }

        #endregion

        #region | btnRemove |

        private void btnRemove_Click(object sender, EventArgs e)
        {
            RemoveSelectedCandidates();
        }

        #endregion

        #region | btnRun |

        private void btnRun_Click(object sender, EventArgs e)
        {
            RunREG();
        }

        #endregion

        #region | lbxActiveCandidates |

        private void lbxActiveCandidates_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(TYP_Candidate))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void lbxActiveCandidates_DragDrop(object sender, DragEventArgs e)
        {
            Candidate obj = (Candidate)e.Data.GetData(TYP_Candidate);
            ReactivateCandidate(obj);
        }

        #endregion

        #region | lbxInitialCandidates |
        
        private void lbxInitialCandidates_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back)
            {
                RemoveSelectedCandidates();
            }
        }

        #endregion

        #region | lbxRejectedCandidates |

        private void lbxRejectedCandidates_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Left)
            {
                Candidate obj = (Candidate)lbxRejectedCandidates.SelectedItem;
                ReactivateCandidate(obj);
            }
        }

        private void lbxRejectedCandidates_MouseDown(object sender, MouseEventArgs e)
        {
            if (lbxRejectedCandidates.SelectedItem != null)
            {
                lbxRejectedCandidates.DoDragDrop((Candidate)lbxRejectedCandidates.SelectedItem, DragDropEffects.All);
            }
        }

        #endregion

        #region | lnkAbout |

        private void lnkAbout_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            ShowAbout();
        }

        #endregion

        #region | txtNewCandidate |

        private void txtNewCandidate_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Up)
            {
                AddCandidate();
            }
        }

        #endregion

        #region | txtReintroductionFactor |

        private void txtReintroductionFactor_TextChanged(object sender, EventArgs e)
        {
            errorProvider.Clear();

            try
            {
                Int32.Parse(txtReintroductionFactor.Text, CultureInfo.CurrentCulture);
            }
            catch (FormatException)
            {
                errorProvider.SetError(txtReintroductionFactor, VLD_NumericInputOnly);
            }
        }

        #endregion

        #endregion

        #region | Private Methods |

        /// <summary>
        /// Adds a new candidate to the list.
        /// </summary>
        private void AddCandidate()
        {
            candidateManager.AllCandidates.Add(txtNewCandidate.Text);
            BindData();
            txtNewCandidate.Focus();
        }

        /// <summary>
        /// Binds the form data.
        /// </summary>
        private void BindData()
        {
            txtNewCandidate.Text = String.Empty;
            lblStepsTotal.Text = candidateManager.StepsExecuted.ToString(CultureInfo.CurrentCulture);
            candidateManagerBindingSource.DataSource = candidateManager;
            allCandidatesBindingSource.DataSource = candidateManager.InitialCandidates;
            activeCandidatesBindingSource.DataSource = candidateManager.ActiveCandidates;
            rejectedCandidatesBindingSource.DataSource = candidateManager.RejectedCandidates;
        }

        /// <summary>
        /// Reactivates the specified candidate.
        /// </summary>
        /// <param name="obj">The candidate to reactivate.</param>
        private void ReactivateCandidate(Candidate obj)
        {
            obj.Rejected = false;
            lbxRejectedCandidates.SelectionMode = SelectionMode.None;
            BindData();
            //btnRun.Enabled = true;
            //btnRun.Focus();
            RunREG();
        }

        /// <summary>
        /// removes all items from the REG process.
        /// </summary>
        private void RemoveAllCandidates()
        {
            candidateManager.AllCandidates.Clear();
            BindData();
            txtNewCandidate.Focus();
        }

        /// <summary>
        /// removes selected items from the REG process.
        /// </summary>
        private void RemoveSelectedCandidates()
        {
            foreach (Object obj in lbxInitialCandidates.SelectedItems)
            {
                candidateManager.AllCandidates.Remove((Candidate)obj);
            }
            BindData();
            txtNewCandidate.Focus();
        }

        /// <summary>
        /// Resets REG to it's default state.
        /// </summary>
        private void Reset()
        {
            candidateManager.Reset();
            txtNewCandidate.Text = String.Empty;
            btnRun.Enabled = true;
            candidateGroup.Enabled = true;
            BindData();
        }

        /// <summary>
        /// Runs the REG process.
        /// </summary>
        private void RunREG()
        {
            candidateGroup.Enabled = false;
            RegRunResult result = candidateManager.Run();
            BindData();
            btnRun.Enabled = false;

            if (result == RegRunResult.CandidateSelected)
            {
                ShowMessageBox(String.Format(CultureInfo.CurrentCulture, STR_CandidateSelected, candidateManager.SelectedCandidate.Name), STR_Caption, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                ShowMessageBox(STR_Reintroduction, STR_Caption, MessageBoxButtons.OK, MessageBoxIcon.Question);
                lbxRejectedCandidates.SelectionMode = SelectionMode.One;
                lbxRejectedCandidates.Focus();
            }

        }

        /// <summary>
        /// Sets the selection mode for all of the list boxes on the form.
        /// </summary>
        /// <remarks>This cocks up if set to None when the form disposes.</remarks>
        /// <param name="mode">The mode to set to.</param>
        private void SetSelectionModeForAllListBoxes(SelectionMode mode)
        {
            lbxActiveCandidates.SelectionMode = mode;
            lbxRejectedCandidates.SelectionMode = mode;
        }

        /// <summary>
        /// Display the application 'About' box.
        /// </summary>
        private void ShowAbout()
        {
            new AboutBox().ShowDialog(this);
        }

        /// <summary>
        /// Shows a MessageBox.
        /// </summary>
        /// <returns>The DialogResult from the MessageBox.</returns>
        /// <param name="text">The text to display.</param>
        /// <param name="caption">The caption to show at the top of the box.</param>
        /// <param name="buttons">The type of buttons to show.</param>
        /// <param name="icon">The icon to display.</param>
        private DialogResult ShowMessageBox(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
        {
            if (this.RightToLeft == RightToLeft.Yes)
            {
                return MessageBox.Show(this, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign);
            }
            else
            {
                return MessageBox.Show(this, text, caption, buttons, icon, MessageBoxDefaultButton.Button1);
            }
        }

        #endregion

        #region | Test Data Methods |

        /// <summary>
        /// Simple test method to populate the candidates box.
        /// </summary>
        private void AddTestCandidates()
        {
            candidateManager.AllCandidates.Add("3:10 To Yuma");
            candidateManager.AllCandidates.Add("Spider Man 2");
            candidateManager.AllCandidates.Add("The Assassination of Jesse James");
            candidateManager.AllCandidates.Add("Becoming Jane");
            candidateManager.AllCandidates.Add("The Lives of Others");
            candidateManager.AllCandidates.Add("Stand By Me");
            candidateManager.AllCandidates.Add("Subway");
            candidateManager.AllCandidates.Add("Star Wars: Episode III");
            candidateManager.AllCandidates.Add("Cloverfield");
            candidateManager.AllCandidates.Add("Paradise Now");
            BindData();
        }

        #endregion

    }
}
